package abg.core.service.sys.impl;


import abg.core.common.cache.Cache;
import abg.core.common.cache.CacheKey;
import abg.core.common.util.MathKit;
import abg.core.common.util.password.PWD;
import abg.core.common.util.valid.base.Valid;
import abg.core.domain.db.SysUser;
import abg.core.domain.sys.MSG;
import abg.core.domain.sys.ServiceException;
import abg.core.domain.sys.UserTokenVo;
import abg.core.mapper.SysUserMapper;
import abg.core.service.sys.SysDictService;
import abg.core.service.sys.SysLoginService;
import abg.core.service.sys.SysUserService;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import static abg.core.domain.db.table.SysUserTableDef.SYS_USER;

/**
 * 用户表实现
 */
@Slf4j
@Service
public class SysLoginServiceImpl implements SysLoginService {
    @Resource
    private Cache<String> cache;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private SysDictService dictService;

    @Resource
    private SysUserService sysUserService;

    /**
     * 管理系统登录
     *
     * @param account       明文账号
     * @param plainPassword 明文密码
     */
    @Valid
    public UserTokenVo managePwdLogin(String account, String plainPassword) {
        //检查缓存禁止登录
        userCacheIsDisableLogin(account);

        //查询用户信息
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.select(SYS_USER.IS_DISABLE, SYS_USER.PASSWORD, SYS_USER.ACCOUNT, SYS_USER.ID);
        wrapper.from(SysUser.class);
        wrapper.where(SYS_USER.EMAIL.eq(account).or(SYS_USER.PHONE.eq(account)).or(SYS_USER.ACCOUNT.eq(account)));
        SysUser userInfo = sysUserMapper.selectOneByQuery(wrapper);

        //账号不存在
        if (userInfo == null) throw new ServiceException(MSG.USER_LOGIN_IS_NOT_EXISTS);

        //账号状态已禁止登录
        if ("1".equals(userInfo.getIsDisable())) throw new ServiceException(MSG.USER_IS_DISABLE);

        //密码输入错误
        if (!PWD.checkPlainPwd(plainPassword, userInfo.getPassword())) {
            loginPwdError(account, "SYS");
            throw new ServiceException(MSG.USER_LOGIN_PASSWORD_ERROR);
        }

        //缓存登录状态
        UserTokenVo userTokenVO = sysUserService.createUserToken(userInfo.getId());
        String accessTokenMd5 = MathKit.getMD5Upper(userTokenVO.getAccessToken());
        cache.set(CacheKey.USER_LOGIN.key() + userInfo.getId(), accessTokenMd5);
        return userTokenVO;
    }

    //检查缓存中是否已经禁止登录，如果已禁止，直接终止逻辑
    private void userCacheIsDisableLogin(String account) {
        String isDisable = cache.getString(CacheKey.USER_SYS_LOGIN_IS_DISABLE.key() + account);
        if (isDisable != null) throw new ServiceException(MSG.USER_LOGIN_ERROR_IS_DISABLE);
    }

    //记录错误次数并抛出异常
    private void loginPwdError(String account, String type) {
        //记录1小时内的错误次数
        String LOGIN_IS_DISABLE = CacheKey.USER_SYS_LOGIN_IS_DISABLE.key() + account;
        String COUNT_ERROR_KEY = CacheKey.USER_LOGIN_ERROR_COUNT.key() + account + "_" + type;
        cache.incr(COUNT_ERROR_KEY, 60 * 60L);
        String errorCount = cache.getString(COUNT_ERROR_KEY);

        //超过10次封60分钟
        if (Integer.parseInt(errorCount) >= 10) {
            cache.set(LOGIN_IS_DISABLE, "1", 60 * 60L);//封60分钟
            cache.set(COUNT_ERROR_KEY, "0");//重置错误次数
            log.error("【系统禁止用户登录提醒】\n【用户错误登录，账号冻结报警，已被冻结60分钟】\n 用户={} ; 类型={} ; LOGIN_IS_DISABLE={}", account, type, LOGIN_IS_DISABLE);
        }

    }

}
